package ip

import (
	"encoding/binary"
	"fmt"
	"reflect"
)

type IPV4Header []byte

// IPVersion ip版本
func (i IPV4Header) IPVersion() uint8 {
	return IPVersion4
}

// IHL 首部长度
func (i IPV4Header) IHL() uint8 {
	return (i[ihl] & 0x0f) * 4
}

// TOS 区分服务
func (i IPV4Header) TOS() uint8 {
	return i[tos]
}

// TotalLength 总长度
func (i IPV4Header) TotalLength() uint16 {
	return binary.BigEndian.Uint16(i[totalLength:])
}

// ID 标识
func (i IPV4Header) ID() uint16 {
	return binary.BigEndian.Uint16(i[id:])
}

// Flags 标志
func (i IPV4Header) Flags() uint8 {
	return i[flags] >> 5
}

// FragmentOffset 片偏移
func (i IPV4Header) FragmentOffset() uint16 {
	return binary.BigEndian.Uint16([]byte{i[fragment] & 0x1F, i[fragment+1]})
}

// TTL 生存时间
func (i IPV4Header) TTL() uint8 {
	return i[ttl]
}

// Protocol 协议
func (i IPV4Header) Protocol() uint8 {
	return i[protocol]
}

// HeaderChecksum 首部校验和
func (i IPV4Header) HeaderChecksum() uint16 {
	return binary.BigEndian.Uint16(i[hCheck:])
}

// SrcAddr 源地址
func (i IPV4Header) SrcAddr() Address {
	return Address(binary.BigEndian.Uint32(i[srcAddr:]))
}

// DstAddr 目标地址
func (i IPV4Header) DstAddr() Address {
	return Address(binary.BigEndian.Uint32(i[dstAddr:]))
}

// Options 可选项
func (i IPV4Header) Options() []byte {
	return i[fixedHL:i.IHL()]
}

// String 使用反射将ip数据报里面的所有字段读取出来
func (i IPV4Header) String() string {
	methods := reflect.ValueOf(i)
	methodTypes := reflect.TypeOf(i)
	var str string
	for a := 0; a < methods.NumMethod(); a++ {
		if methodTypes.Method(a).Name == "String" {
			continue
		}
		str += fmt.Sprint(
			methodTypes.Method(a).Name, ":",
			methods.Method(a).Call([]reflect.Value{})[0].Interface(), ";",
		)
	}
	if len(str) != 0 {
		return fmt.Sprintf("{%s}", str)
	}
	return str
}

// MarshalField 将Field的字段序列化到buffer里面
func MarshalField(ipF IPV4Field) []byte {
	buf := make([]byte, 0, 20)
	buf = append(buf, (ipF.Version<<4)|ipF.IHL)
	buf = append(buf, ipF.TOS)
	binary.BigEndian.PutUint16(buf[totalLength:], ipF.TL)
	binary.BigEndian.PutUint16(buf[id:], ipF.ID)
	binary.BigEndian.PutUint16(buf[flags:], (uint16(ipF.Flags)<<13)|ipF.FragOff)
	buf = append(buf, ipF.TTL)
	buf = append(buf, ipF.Protocol)
	binary.BigEndian.PutUint16(buf[hCheck:], ipF.HCheck)
	binary.BigEndian.PutUint32(buf[hCheck:], uint32(ipF.SrcAddr))
	binary.BigEndian.PutUint32(buf[hCheck:], uint32(ipF.DstAddr))
	if ipF.Options != nil {
		buf = append(buf, ipF.Options...)
	}
	padding := len(buf) % 4
	for i := 0; i < padding; i++ {
		buf = append(buf, 0)
	}

	return buf
}

// UnmarshalField 将buffer反序列化到field里面
func UnmarshalField(ipH IPV4Header) *IPV4Field {
	ipv4Field := IPV4Field{
		Version:  ipH.IPVersion(),
		IHL:      ipH.IHL(),
		TOS:      ipH.TOS(),
		TL:       ipH.TotalLength(),
		ID:       ipH.ID(),
		Flags:    ipH.Flags(),
		FragOff:  ipH.FragmentOffset(),
		TTL:      ipH.TTL(),
		Protocol: ipH.Protocol(),
		HCheck:   ipH.HeaderChecksum(),
		SrcAddr:  ipH.SrcAddr(),
		DstAddr:  ipH.DstAddr(),
		Options:  ipH.Options(),
	}
	return &ipv4Field
}
